package regression;

import java.util.Calendar;
import java.util.Date;
import java.util.Map;

import flanagan.analysis.Regression;

/**
 * Singleton class calculating linear regresion of accidents number.
 * 
 * @author Dawid Nejman
 * @version 1.0
 */
public class AccidentRegression implements IRegression {

	private static IRegression instance;
	private Regression regression;
	private final Map<Date, Integer> data;

	private AccidentRegression(Map<Date, Integer> data) {
		this.data = data;
		calculateRegression();
	}

	/**
	 * Static method for retrieving instance of {@code IRegression} instance.
	 * 
	 * @param data
	 *            database statistical data about car number in Sweden.
	 * @return class only instance.
	 */
	public static IRegression getInstance(Map<Date, Integer> data) {
		if (instance == null)
			instance = new AccidentRegression(data);
		return instance;
	}

	/*
	 * Converts date into internal format (double) in order to make regression
	 * more accurate.
	 */
	private double dateToDouble(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		double time = cal.get(Calendar.YEAR);
		return time;
	}

	private void calculateRegression() {
		double[] doubleXArray = new double[data.size()];
		double[] doubleYArray = new double[data.size()];
		Integer[] intArray = new Integer[data.size()];
		Date[] dateArray = new Date[data.size()];

		intArray = data.values().toArray(intArray);
		dateArray = data.keySet().toArray(dateArray);

		for (int i = 0; i < data.size(); i++) {
			doubleXArray[i] = dateToDouble(dateArray[i]);
			doubleYArray[i] = intArray[i].doubleValue();
		}

		this.regression = new Regression(doubleXArray, doubleYArray);
		this.regression.linear();
	}

	/**
	 * @see regression.IRegression#saveDataToFile(java.lang.String)
	 */
	@Override
	public void saveDataToFile(String filename) {
		this.regression.print(filename);
	}

	/**
	 * @see regression.IRegression#getNumberFor(java.util.Date)
	 */
	@Override
	public double getNumberFor(Date date) {
		double time = dateToDouble(date);
		double[] estimates = this.regression.getBestEstimates();
		return (int) (estimates[0] + estimates[1] * time);
	}

}
